#include <boost/shared_ptr.hpp>

#include "engine/task.h"
#include "engine/result_codes.h"
#include "engine/kernel.h"

#include "cppunit/TestFixture.h"
#include "cppunit/extensions/HelperMacros.h"


using namespace engine;

class KernelTest : public CppUnit::TestFixture {    
    CPPUNIT_TEST_SUITE(KernelTest);
    CPPUNIT_TEST(testAddTask); 
    CPPUNIT_TEST(testSuspend);  
    CPPUNIT_TEST(testDuplicates);
    CPPUNIT_TEST(testResume);
    //CPPUNIT_TEST(testKernelLoop);
    CPPUNIT_TEST_SUITE_END();

    class SampleTask : public Task {
    public:
        SampleTask(long priority) : Task(priority) {}
        int Start() {return base::OK_OK;}
        int Update() {return base::OK_OK;}
        int Stop(){ return base::OK_OK;}
    };

    class SampleFailingTask : public Task {
    public:
        SampleFailingTask(long priority) : Task(priority) {}
        int Start() {return ER_TASK_START_FAIL;}
        int Update() {return base::OK_OK;}
        int Stop() {return base::OK_OK;}
    };

public:  
    void setUp() {  
        task_1_ = boost::shared_ptr<Task>(new SampleTask(10));
        task_2_ = boost::shared_ptr<Task>(new SampleTask(20));
        task_3_ = task_1_;
        task_4_ = task_2_;
        task_5_ = boost::shared_ptr<Task>(new SampleFailingTask(40));     

        active_task_count_ = Kernel::GetActiveTaskCount();
        paused_task_count_ = Kernel::GetPausedTaskCount();
    }  
    
    void tearDown() {  

    }  
    
    void testAddTask() { 
        active_task_count_ = Kernel::GetActiveTaskCount();
        paused_task_count_ = Kernel::GetPausedTaskCount();
        
        //AddTask() result code indicates failure for first task
        CPPUNIT_ASSERT(Kernel::AddTask(task_1_) >= 0); 

        //AddTask() result code indicates failure for subsequent tasks
        CPPUNIT_ASSERT(Kernel::AddTask(task_2_) >= 0); 

        //Active Task Count indicates failure
        CPPUNIT_ASSERT(active_task_count_ == Kernel::GetActiveTaskCount() - 2); 

        //Allowed addition of a task that fails task::Start()
        CPPUNIT_ASSERT(Kernel::AddTask(task_5_) < 0);
    }     
    void testSuspend() { 
        Kernel::AddTask(task_1_);
        Kernel::AddTask(task_2_);
        active_task_count_ = Kernel::GetActiveTaskCount();
        paused_task_count_ = Kernel::GetPausedTaskCount();

        //SuspendTask() result code indicates failure
        CPPUNIT_ASSERT(Kernel::SuspendTask(task_1_) >= 0);

        //Allowed suspension of paused task
        CPPUNIT_ASSERT(Kernel::SuspendTask(task_1_) < 0);
        
        //Allowed suspension of a task not in kernel
        CPPUNIT_ASSERT(Kernel::SuspendTask(task_5_) < 0);
        
        //Active Task Count indicates failure
        CPPUNIT_ASSERT(active_task_count_ == Kernel::GetActiveTaskCount() + 1);
        
        //Paused Task Count indicates failure
        CPPUNIT_ASSERT(paused_task_count_ == Kernel::GetPausedTaskCount() - 1);
    }
    void testDuplicates() {
        Kernel::AddTask(task_1_);
        Kernel::SuspendTask(task_1_);
        Kernel::AddTask(task_2_);

        active_task_count_ = Kernel::GetActiveTaskCount();
        paused_task_count_ = Kernel::GetPausedTaskCount();

        //Allowed insertion of duplicate task, duplicate is paused
        CPPUNIT_ASSERT(Kernel::AddTask(task_3_) < 0);
    
        //Allowed insertion of duplicate task, duplicate is active
        CPPUNIT_ASSERT(Kernel::AddTask(task_4_) < 0);

        //Active Task Count indicates failure
        CPPUNIT_ASSERT(active_task_count_ == Kernel::GetActiveTaskCount());

        //Paused Task Count indicates failure
        CPPUNIT_ASSERT(paused_task_count_ == Kernel::GetPausedTaskCount()); 

    }
    void testResume() {
        Kernel::AddTask(task_1_);
        Kernel::SuspendTask(task_1_);

        Kernel::AddTask(task_2_);

        active_task_count_ = Kernel::GetActiveTaskCount();
        paused_task_count_ = Kernel::GetPausedTaskCount();

        //ResumeTask() result code indicates failure
        CPPUNIT_ASSERT(Kernel::ResumeTask(task_1_) >= 0);
        //Allowed resuming an active task
        CPPUNIT_ASSERT(Kernel::ResumeTask(task_2_) < 0);
        
        //Allowed resuming a task not in kernel
        CPPUNIT_ASSERT(Kernel::ResumeTask(task_5_) < 0);

        //Active Task Count indicates failure
        CPPUNIT_ASSERT(active_task_count_ == Kernel::GetActiveTaskCount() - 1);
        
        //Active Task Count indicates failure
        CPPUNIT_ASSERT(paused_task_count_ == Kernel::GetPausedTaskCount() + 1);
    }

    //void testKernelLoop() {
    //    Kernel::AddTask(task_1_);
    //    Kernel::SuspendTask(task_1_);

    //    Kernel::AddTask(task_2_);
    //    Kernel::SuspendTask(task_2_);

    //    //failed to exit loop when all tasks paused
    //    CPPUNIT_ASSERT(engine::Kernel::Execute() >= 0);

    //    Kernel::ResumeTask(task_1_);
    //    Kernel::ResumeTask(task_2_);

    //    active_task_count_ = Kernel::GetActiveTaskCount();
    //    paused_task_count_ = Kernel::GetPausedTaskCount();

    //    //RemoveTask() result code indicates failure, active task
    //    CPPUNIT_ASSERT(Kernel::KillTask(task_1_) >= 0);

    //    //RemoveTask() result code indicates failure, paused task
    //    CPPUNIT_ASSERT(Kernel::KillTask(task_2_) < 0);
    //    
    //    //Allowed removing a task not in kernel
    //    CPPUNIT_ASSERT(Kernel::KillTask(task_5_) < 0);
    //    
    //    //failed to exit loop when there are no tasks
    //    CPPUNIT_ASSERT(Kernel::Execute() >= 0);
    //    
    //    //Active Task Count indicates failure
    //    CPPUNIT_ASSERT(active_task_count_ == 0);

    //    //Paused Task Count indicates failure
    //    CPPUNIT_ASSERT(paused_task_count_ == Kernel::GetPausedTaskCount());

    //    Kernel::AddTask(task_1_);
    //    Kernel::AddTask(task_2_);
    //    
    //    active_task_count_ = Kernel::GetActiveTaskCount();
    //    paused_task_count_ = Kernel::GetPausedTaskCount();
    //    
    //    //KillAllTasks() result code indicates error
    //    CPPUNIT_ASSERT(Kernel::KillAllTasks() >= 0);

    //    //failed to remove dead tasks and exit loop
    //    CPPUNIT_ASSERT(Kernel::Execute() >= 0);

    //    //Active Task Count indicates failure
    //    CPPUNIT_ASSERT(active_task_count_ == 0);
    //    
    //    //Paused Task Count indicates failure
    //    CPPUNIT_ASSERT(paused_task_count_ == Kernel::GetPausedTaskCount());
    //}
private:
    boost::shared_ptr<Task> task_1_;
    boost::shared_ptr<Task> task_2_;
    boost::shared_ptr<Task> task_3_;
    boost::shared_ptr<Task> task_4_;
    boost::shared_ptr<Task> task_5_;

    int active_task_count_;
    int paused_task_count_; 
};

CPPUNIT_TEST_SUITE_REGISTRATION(KernelTest);
